<?php
namespace App\Http\Controllers\Payment;

use App\Http\Controllers\Controller;
use App\Jobs\AlipayRefundJob;
use App\Jobs\ClosePaymentJob;
use App\Jobs\PushMsgJob;
use App\Jobs\SendSystemMsgJob;
use App\Jobs\ShopTransJob;
use App\Libraries\Tools\ConstVar;
use App\Libraries\Tools\Msg;
use App\Libraries\Tools\Tools;
use App\Models\HongBao\HongBao;
use App\Models\Order\Order;
use App\Models\Post\Post;
use App\Models\Post\PostPurchase;
use App\Models\Product\Product;
use App\Models\Product\ProductPurchase;
use App\Models\Shop\Shop;
use App\Models\Shop\ShopCoupon;
use App\Models\Shop\ShopCouponPurchase;
use App\Models\Shop\ShopManager;
use App\Models\User\Address;
use App\Models\User\Balance;
use App\Models\User\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;


class AliPayController extends Controller{

    //sandbox
//    protected $gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
//    protected $appId = "2016080600178049";
//    protected $rsaPrivateKey = 'MIIEowIBAAKCAQEA1XnCQmMeXHCn/Sprm7+7Lrc9W8U+eHVmdTJPWd1c0+/n7dyDe1myBb0uBiFI6ATrl7QcuZ9f71cTDw72TtC4lBXFDh5TO4sdlqpGgZ2IPMZcD6CLAYpfxQn1re7JIt/jOguC/EaruV7ItR1NVjBrnenYjwVJSPUGcfvPuUWJqQwXvTRACq8H151tZpOLsGkSerrBjh75K/lETjiDMn7pswrHcT5FmXN+FpKOTIrYnW1pOeJQWUOunDfPZXHfvpJHslY8RgPeM1CmZRrrcIBJwFWNGCbdE+97ZDcfLCgK2xQBf0wBHqb5XB7zv9cWqZ6FH/Ti8N9Tt+VImFgHZz1WpQIDAQABAoIBACLfex6BNqp/NNIkpeORlLBy+rENLcFb3Fr01wWlJc7xd//hcBEse+p4FxalRVWxyBLGN5MTOAbPQKvLE+2YJy75x3Eg/xPRDApa0p3F8EWNWeirn0mnIzH7CIlbYrwxutr2mnU/zjnABCWiHcogqtPnKZtjj689Z8ojCrIHbA+TP8AGihfNusrKLW4TMK5a1X310c95X+8ipgfZ2h4yXzUsozzv/SGw1nsfup5UPKsqSz5ScSInz1u07DaAPp+JNwul05P3uBUUEfLWrMHj8WDu1Bvy6rXdtqB2TZ0HWHTV27i37m0D6alpEEE0NsyKnoUO5EWvKRuLuDyl9f4SytkCgYEA7uTrKIrUcrhGBaJWcbFLRUVAdzBW7mv+4QoXjBlEmqDuDVWHB0iAMjiLTcjpvMIrdrd1SHdWNC6Mt1RreXacRNZbBUQnLXu42EWP2Lk2rB1vIIydWgHvjd/KiQrvo3rf8vliKn227Yxpw3oMidRXIFA9AaYSLtKS4iDuyrrDRo8CgYEA5MLmw3cO+6TXhQdSB70hoZMiA3Xzq9sIRsySjBFruZW6AlUG6n0wH7oblU3a51xDRs7Oy5xGG2oTKQKGA5QNYg45HgAcAfNSMnu7evVAEYo3179B//eLCPa/jwUf+m3fljuakTbC1iteTQ5aNlmSsM+WwRfVu8M0LlAMKCgVCYsCgYEApqZ+/XtLlPPDtS54CzvY/GvA+uR34D7qQOafYpZF63CUYCzn00baVy5mz05277ysQVbdtD27nw9SDpoPl14MyWCXgmb2xZ3nZsev/0nFP/AQk65EHoP3LwuM6Gj+nxaan48k0et87t3i8gB0OrosRVh0FnBZgtxWpvS+YCJFEzUCgYBWSzdlsLnUL4ClS/ejt7LCEpCYIZyDzaI3ot/9Om0amuKKEq0DM6o9raTOE4pqECHIyia0JAVGPiNwKuWG4AiUXq0pJf1qtvDg3lAAuBctBqi+GAW7mxO1k+768oH3pA7dyyopcTDaPY3bH3jkW7G8RPKncGhN5fr/JW8Qjt4wtQKBgCitoqkPHW3OUk9JOe15STlwANDc1YiwV65OnhPpWEGE4uAX2sNpwzhPUhR6Y8GH6WtY8EhuMyx+bkZsLwOasmW0htVFt5E2kPRvA9gnme31U/v0s9DuindpmlHDMm3P5TtluealZ4tK0ThJs5b8U8OkiswZkKaAszRMlaPm9GCj';
//    protected $alipayrsaPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+hx6lWVMR9z1Itzv0h8eJRAb9WWsdGmV/RdgwJIOqQ8NORxh8vTeZ6ZbyeuShlqyI73alBJFwzcKXTreENwYfluqklRtLGDhBgo/Rr9dZb9AfyksKNjBda14+HiwVkX17uP7PDlKHF+Oa5SByJOjR3GdjmeD/VhROcgqQxKvCnW3tawKRk5v8eG3fcdN5UgCUjuMkSje7SqtOvExYrwe7v410mZK2YwAE+gUkQxIIbFZq3A9NO3tv26n8F4gxfr1gS+pchA4p3OE5xomKPyV/Dbh2tJ+E72u38mNXW5IxBE9/RLJ+d3Xt2hkIi220MyUJgPqdJ7YizikqlBWUqzUjQIDAQAB';

    protected $order;
    protected $post;
    protected $shopCoupon;
    protected $shopCouponPurchase;
    protected $postPurchase;
    protected $auth_user;
    protected $address;
    protected $product;
    protected $productPurchase;
    protected $user;
    protected $balance;
    protected $hongBao;
    protected $out_trade_no;
    protected $sid;

    public function __construct(Order $order, Post $post, User $user, ShopCoupon $shopCoupon,
                                ShopCouponPurchase $shopCouponPurchase,
                                PostPurchase $postPurchase, Address $address,
                                Product $product, ProductPurchase $productPurchase,
                                Balance $balance, HongBao $hongBao){
        $this->order = $order;
        $this->post = $post;
        $this->shopCoupon = $shopCoupon;
        $this->shopCouponPurchase = $shopCouponPurchase;
        $this->postPurchase = $postPurchase;
        $this->auth_user = Auth::user();
        $this->address = $address;
        $this->product = $product;
        $this->productPurchase = $productPurchase;
        $this->user = $user;
        $this->balance = $balance;
        $this->hongBao = $hongBao;

        $this->gatewayUrl = env('ALIPAY_GATEWAY');
        $this->appId = env('ALIPAY_APPID');
        $this->rsaPrivateKey = env('ALIPAY_RSA_PRIVATE_KEY');
        $this->alipayrsaPublicKey = env('ALIPAY_RSA_PUBLISH_KEY');
    }

    /**
     * 生成订单信息
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function orderInfo(Request $request){
        $validator = Validator::make($request->all(), [
            'id' => 'required|integer',
            'type' => 'required|in:1,2,3,4,5,6',//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
            'address_id' => 'integer',
            'quantity' => 'integer',
            'hong_bao_id' => 'integer',
            'transfer_amount' => 'numeric|required_if:type,3,5,6',
        ], [
            'id.required' => '10001',
            'id.integer' => '10002',
            'type.required' => '10001',
            'type.in' => '10002',
            'address_id.integer' => '10002',
            'quantity.integer' => '10002',
            'hong_bao_id.integer' => '10002',
            'transfer_amount.numeric' => '10002',
            'transfer_amount.required_if' => '10001',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        switch($request['type']){//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
            case ConstVar::$ORDER_TYPE_POST:
                $model = $this->post;
                $model_ext = $this->postPurchase;
                break;
            case ConstVar::$ORDER_TYPE_PRODUCT:
                $model = $this->product;
                $model_ext = $this->address;
                break;
            case ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP:
                $model = new User();
                $model_ext = new Shop();
                break;
            case ConstVar::$ORDER_TYPE_COUPON:
                $model = $this->shopCoupon;
                $model_ext = $this->hongBao;
                break;
            case ConstVar::$ORDER_TYPE_TRANSFER_TO_USER:
                $model = new User();
                $model_ext = null;
                break;
            default:
                return $this->sendFailResponse(400, 50001);
        }

        $rs = $this->order->logic($request, $this->auth_user, ConstVar::$ORDER_CHANNEL_ALIPAY, $model, $model_ext);
        if($rs['code'] != 200){
            return $this->sendFailResponse(400, $rs['code']);
        }
        $job = (new ClosePaymentJob($rs['data']['out_trade_no']))->delay(Carbon::now()->addMinutes(ConstVar::$PAYMENT_CLOSE_DELAY));
        dispatch($job);

        $real_amount = $this->order->total_amount - $this->order->hong_bao_amount;

        $aop = new \AopClient();
        $aop->gatewayUrl = $this->gatewayUrl;
        $aop->appId = $this->appId;
        $aop->rsaPrivateKey = $this->rsaPrivateKey;
        $aop->format = "json";
        $aop->charset = "UTF-8";
        $aop->signType = "RSA2";
        $aop->alipayrsaPublicKey = $this->alipayrsaPublicKey;
        $ali_request = new \AlipayTradeAppPayRequest();
        $bizcontent = "{\"body\":\"{$rs['data']['body']}\","
            . "\"subject\": \"{$rs['data']['subject']}\","
            . "\"out_trade_no\": \"{$rs['data']['out_trade_no']}\","
            . "\"timeout_express\": \"5m\","
            . "\"total_amount\": \"{$real_amount}\","
            . "\"product_code\":\"QUICK_MSECURITY_PAY\""
            . "}";
        if(env('APP_ENV') == 'local'){
            $ali_request->setNotifyUrl("http://api.beboy.me:8081/api/payment/ali/notify");
        }else{
            $ali_request->setNotifyUrl("http://api.beboy.me/api/payment/ali/notify");
        }
        $ali_request->setBizContent($bizcontent);
        $response = $aop->sdkExecute($ali_request);
        Cache::put($rs['data']['out_trade_no'], $response, Carbon::now()->addMinutes(15));
        return $this->sendSuccessResponse(['info'=>$response]);
    }

    /**
     * alipay回调
     * @return string
     */
    public function notify(){
        $aop = new \AopClient;
        $aop->alipayrsaPublicKey = $this->alipayrsaPublicKey;
        $flag = $aop->rsaCheckV1($_POST, NULL, "RSA2");
        if($flag){
//            Log::debug(\GuzzleHttp\json_encode($_POST));
            DB::beginTransaction();
            try{
                $order_info = explode('_', $_POST['out_trade_no']);
                $order = $this->order->where('id', $order_info[0])->firstOrFail();
                if($_POST['trade_status'] == 'TRADE_SUCCESS' || $_POST['trade_status'] == 'TRADE_FINISHED'){
                    if(empty($order->status)){//0-待支付 1-成功 2-失败 3-退款
                        $order->status = ConstVar::$ORDER_STATUS_SUCCESS;
                    }else{
                        return 'success';
                    }
                    $order->sid = $_POST['trade_no'];
                    $order->buyer_channel_id = $_POST['buyer_id'];
                    $order->buyer_channel_account = $_POST['buyer_logon_id'];
                    $order->receipt_amount = $_POST['receipt_amount'];
                    $order->save();
                    switch($order_info[1]){
                        case ConstVar::$ORDER_TYPE_POST:
                            $postPurchase = $this->postPurchase->where('order_id',$order_info[0])->first();
                            $postPurchase->status=1;
                            $postPurchase->save();
                            $purchase_id = $postPurchase->id;
                            $this->balance->add(
                                Msg::alipay_consumption().'_'.Msg::balance_post_profit($order_info[2]),
                                $order->user_id,
                                $order_info[3],
                                ConstVar::$BALANCE_CHANNEL_ALIPAY,
                                ConstVar::$BALANCE_CHANNEL_BALANCE,
                                ConstVar::$ORDER_TYPE_POST,
                                $order_info[2],
                                $order->total_amount,
                                $purchase_id
                            );
                            break;
                        case ConstVar::$ORDER_TYPE_PRODUCT:
                            $productPurchase = $this->productPurchase->where('order_id',$order_info[0])->first();
                            $productPurchase->status=1;
                            $productPurchase->save();
                            $purchase_id = $productPurchase->id;
                            $this->balance->add(//消费记录
                                Msg::alipay_consumption().'_'.Msg::balance_product_profit($order_info[2]),
                                $order->user_id,
                                0,
                                ConstVar::$BALANCE_CHANNEL_ALIPAY,
                                ConstVar::$BALANCE_CHANNEL_BALANCE,
                                ConstVar::$ORDER_TYPE_PRODUCT,
                                $order_info[2],
                                $order->receipt_amount,
                                $purchase_id,
                                $order->hong_bao_id,
                                $order->hong_bao_amount,
                                ConstVar::$BALANCE_STATUS_SUCCESS,
                                ConstVar::$BALANCE_TYPE_USER,
                                ConstVar::$BALANCE_TYPE_SYSTEM
                            );
                            $product = Product::find($productPurchase->product_id);
                            if($product->category == 2){
//                              todo      dispatch(new MLMJob($user_id, $channel, $product_id, $this->id));
                                (new User)->addVIP($order->user_id, $product->level, $product->validity);
                            }
                            break;
                        case ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP:
                            Shop::where('shop_id', $order_info[2])->increment('balance', $order->total_amount);
                            $owner = ShopManager::where('shop_id', $order_info[2])
                                ->where('status', 1)->where('level', 1)->first();
                            $this->balance->add(//transfer记录
                                Msg::alipay_consumption().'_'.Msg::balance_transfer_profit(),
                                $order->user_id,
                                $order_info[2],
                                ConstVar::$BALANCE_CHANNEL_ALIPAY,
                                ConstVar::$BALANCE_CHANNEL_BALANCE,
                                ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP,
                                $order_info[2],
                                $order->total_amount,
                                0,
                                $order->hong_bao_id,
                                $order->hong_bao_amount,
                                ConstVar::$BALANCE_STATUS_SUCCESS,
                                ConstVar::$BALANCE_TYPE_USER,
                                ConstVar::$BALANCE_TYPE_SHOP
                            );
                            if(!empty($owner)){
                                dispatch(new SendSystemMsgJob([$owner->user_id], Msg::transfer_to_shop($order->total_amount), 0));
                                dispatch(new PushMsgJob([$owner->user_id], Msg::transfer_to_shop($order->total_amount), 0));
                                dispatch(new ShopTransJob($order->id, $owner->user_id, $order_info[2]));
                            }
                            break;
                        case ConstVar::$ORDER_TYPE_COUPON:
                            $shopCouponPurchase = $this->shopCouponPurchase->where('order_id',$order_info[0])->first();
                            $shopCouponPurchase->status=0;
                            $shopCouponPurchase->save();
                            $purchase_id = $shopCouponPurchase->id;
                            $this->balance->add(//消费记录
                                Msg::alipay_consumption().'_'.Msg::balance_coupon_profit($order_info[2]),
                                $order->user_id,//from_id
                                0,
                                ConstVar::$BALANCE_CHANNEL_ALIPAY,
                                ConstVar::$BALANCE_CHANNEL_BALANCE,
                                ConstVar::$ORDER_TYPE_COUPON,
                                $order_info[2],//coupon_id
                                $order->receipt_amount,
                                $purchase_id,
                                $order->hong_bao_id,
                                $order->hong_bao_amount,
                                ConstVar::$BALANCE_STATUS_SUCCESS,
                                ConstVar::$BALANCE_TYPE_USER,
                                ConstVar::$BALANCE_TYPE_SYSTEM
                            );
                            break;
                        case ConstVar::$ORDER_TYPE_TRANSFER_TO_USER:
                            User::where('user_id', $order_info[2])->increment('balance', $order->total_amount);
                            $this->balance->add(//transfer记录
                                Msg::alipay_consumption().'_'.Msg::balance_transfer_profit(),
                                $order->user_id,
                                $order_info[2],
                                ConstVar::$BALANCE_CHANNEL_ALIPAY,
                                ConstVar::$BALANCE_CHANNEL_BALANCE,
                                ConstVar::$ORDER_TYPE_TRANSFER_TO_USER,
                                $order_info[2],
                                $order->total_amount,
                                0,
                                $order->hong_bao_id,
                                $order->hong_bao_amount,
                                ConstVar::$BALANCE_STATUS_SUCCESS,
                                ConstVar::$BALANCE_TYPE_USER,
                                ConstVar::$BALANCE_TYPE_USER
                            );
                            break;
                        case ConstVar::$ORDER_TYPE_HONGBAO:
                            DB::rollBack();
                            return 'fail';
                            break;
                        default:
                            DB::rollBack();
                            return 'fail';
                            break;
                    }
                }elseif($_POST['trade_status'] == 'TRADE_CLOSED'){
                    if(empty($order->status)){//0-待支付 1-成功 2-失败 3-退款
                        $order->status = ConstVar::$ORDER_STATUS_FAIL;
                    }elseif($order->status == ConstVar::$ORDER_STATUS_SUCCESS){
                        $order->status = ConstVar::$ORDER_STATUS_REFUNDED;
                    }
                    $order->save();
                }
            }catch (\Exception $e){
                DB::rollBack();
                Log::critical('alipay fail', $_POST);
                Log::critical('alipay fail', ['msg'=>$e->getTraceAsString()]);
                return 'fail';
            }
            DB::commit();
            return 'success';
        }else{
            return 'fail';
        }
    }

    /**
     * 退款
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function refund(Request $request){
        $validator = Validator::make($request->all(), [
            'id' => 'required|integer',
            'type' => 'required|in:1,2,3,4,5,6',//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
        ], [
            'id.required' => '10001',
            'id.integer' => '10002',
            'type.required' => '10001',
            'type.in' => '10002',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        switch($request['type']){//1-post 2-product 3-transfer 4-coupon
            case 1:
                return $this->sendFailResponse(400, 50001);
            case 2:
                return $this->sendFailResponse(400, 50001);
            case 3:
                //todo
                return $this->sendFailResponse(400, 50001);
            case 4:
                $shopCouponPurchase = $this->shopCouponPurchase->where('id', $request['id'])->first();
                if(empty($shopCouponPurchase) || empty($shopCouponPurchase->order_id)){
                    return $this->sendFailResponse(400, 40400);
                }
                if($shopCouponPurchase->status != ConstVar::$PURCHASE_STATUS_UNUSED){
                    return $this->sendFailResponse(400, 40001);
                }

                $order = $this->order->where('id', $shopCouponPurchase->order_id)->first();
                if(empty($order)){
                    return $this->sendFailResponse(400, 40400);
                }
                if($order->status != ConstVar::$ORDER_STATUS_SUCCESS){
                    return $this->sendFailResponse(400, 40001);
                }
                if($order->user_id != Auth::id() || $shopCouponPurchase->user_id != Auth::id()){
                    return $this->sendFailResponse(400, 40001);
                }
                $shopCouponPurchase->status = ConstVar::$PURCHASE_STATUS_REFUNDING;
                $order->status = ConstVar::$ORDER_STATUS_REFUNDING;
                $shopCouponPurchase->save();
                $order->save();
                $this->balance->where('purchase_id', $shopCouponPurchase->id)
                    ->where('from_id', $shopCouponPurchase->user_id)->update(['status'=>2]);
                $this->balance->add(//消费记录
                    Msg::system_refund().'_'.Msg::system_refund(),
                    0,//from_id
                    $shopCouponPurchase->user_id,
                    ConstVar::$BALANCE_CHANNEL_BALANCE,
                    ConstVar::$BALANCE_CHANNEL_ALIPAY,
                    ConstVar::$ORDER_TYPE_COUPON,
                    $shopCouponPurchase->coupon_id,//coupon_id
                    $order->receipt_amount,
                    $shopCouponPurchase->id,
                    $order->hong_bao_id,
                    $order->hong_bao_amount,
                    ConstVar::$BALANCE_STATUS_SUCCESS,
                    ConstVar::$BALANCE_TYPE_SYSTEM,
                    ConstVar::$BALANCE_TYPE_USER,
                    ConstVar::$BALANCE_REFUND
                );
                $this->out_trade_no = $order->out_trade_no;
                $this->sid = $order->sid;
                break;
            default:
                return $this->sendFailResponse(400, 50001);
        }

        $aop = new \AopClient();
        $aop->gatewayUrl = $this->gatewayUrl;
        $aop->appId = $this->appId;
        $aop->rsaPrivateKey = $this->rsaPrivateKey;
        $aop->format = "json";
        $aop->charset = "UTF-8";
        $aop->signType = "RSA2";
        $aop->alipayrsaPublicKey = $this->alipayrsaPublicKey;
        $ali_request = new \AlipayTradeRefundRequest();
        $ali_request->setBizContent("{" .
            "\"out_trade_no\":\"{$this->out_trade_no}\"," .
            "\"trade_no\":\"{$this->sid}\"," .
            "\"refund_amount\":{$order->receipt_amount}," .
            "\"refund_reason\":\"正常退款\"," .
            "\"out_request_no\":\"{$order->id}\"" .
            "  }");
        dispatch((new AlipayRefundJob($aop, $ali_request, $order, $shopCouponPurchase, Auth::id()))->delay(Carbon::now()->addMinutes(ConstVar::$PAYMENT_REFUND_DELAY)));

        return $this->sendSuccessResponse([]);
    }

//    public function trans(){
//        $aop = new \AopClient();
//        $aop->gatewayUrl = $this->gatewayUrl;
//        $aop->appId = $this->appId;
//        $aop->rsaPrivateKey = $this->rsaPrivateKey;
//        $aop->format = "json";
//        $aop->charset = "UTF-8";
//        $aop->signType = "RSA2";
//        $aop->alipayrsaPublicKey = $this->alipayrsaPublicKey;
//        $ali_request = new \AlipayFundTransToaccountTransferRequest ();
//        $ali_request->setBizContent("{" .
//            "\"out_biz_no\":\"".time()."\"," .
//            "\"payee_type\":\"ALIPAY_LOGONID\"," .
//            "\"payee_account\":\"15018444821\"," .
//            "\"amount\":\"0.1\"," .
//            "\"payer_show_name\":\"夜城\"," .
//            "\"payee_real_name\":\"古维\"," .
//            "\"remark\":\"企业转账\"" .
//            "  }");
//        $result = $aop->execute ($ali_request);
//        $responseNode = str_replace(".", "_", $ali_request->getApiMethodName()) . "_response";
//        $resultCode = $result->$responseNode->code;
//        if(!empty($resultCode)&&$resultCode == 10000){
//            echo "成功";
//        } else {
//            echo $result->$responseNode->sub_msg;
//        }
//    }
}